package com.wondersgroup.core.util;

import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import org.apache.commons.lang.StringUtils;

/**
 * mysql汉字拼音首字母检索工具
 *
 * @author wanglei
 */
public class PinYinUtil {
    
    private static final Logger log = Logger.getLogger(PinYinUtil.class.getName());

    public static final int[] A = {45217, 45252};
    public static final int[] B = {45253, 45760};
    public static final int[] C = {45761, 46317};
    public static final int[] D = {46318, 46825};
    public static final int[] E = {46826, 47009};
    public static final int[] F = {47010, 47296};
    public static final int[] G = {47297, 47613};
    public static final int[] H = {47614, 48118};
    public static final int[] I = {};
    public static final int[] J = {48119, 49061};
    public static final int[] K = {49062, 49323};
    public static final int[] L = {49324, 49895};
    public static final int[] M = {49896, 50370};
    public static final int[] N = {50371, 50613};
    public static final int[] O = {50614, 50621};
    public static final int[] P = {50622, 50905};
    public static final int[] Q = {50906, 51386};
    public static final int[] R = {51387, 51445};
    public static final int[] S = {51446, 52217};
    public static final int[] T = {52218, 52697};
    public static final int[] U = {};
    public static final int[] V = {};
    public static final int[] W = {52698, 52979};
    public static final int[] X = {52980, 53688};
    public static final int[] Y = {53689, 54480};
    public static final int[] Z = {54481, 55289};

    /**
     * 获取字符对应的检索范围, 对于i, u, v三个字符由于没有汉字对应则返回长度为0的数组
     *
     * @param firstChar
     * @return
     */
    public static int[] getCharRange(char firstChar) {
        switch (firstChar) {
            case 'A':
                return A;
            case 'B':
                return B;
            case 'C':
                return C;
            case 'D':
                return D;
            case 'E':
                return E;
            case 'F':
                return F;
            case 'G':
                return G;
            case 'H':
                return H;
            case 'I':
                return I;
            case 'J':
                return J;
            case 'K':
                return K;
            case 'L':
                return L;
            case 'M':
                return M;
            case 'N':
                return N;
            case 'O':
                return O;
            case 'P':
                return P;
            case 'Q':
                return Q;
            case 'R':
                return R;
            case 'S':
                return S;
            case 'T':
                return T;
            case 'U':
                return U;
            case 'V':
                return V;
            case 'W':
                return W;
            case 'X':
                return X;
            case 'Y':
                return Y;
            case 'Z':
                return Z;
            case 'a':
                return A;
            case 'b':
                return B;
            case 'c':
                return C;
            case 'd':
                return D;
            case 'e':
                return E;
            case 'f':
                return F;
            case 'g':
                return G;
            case 'h':
                return H;
            case 'i':
                return I;
            case 'j':
                return J;
            case 'k':
                return K;
            case 'l':
                return L;
            case 'm':
                return M;
            case 'n':
                return N;
            case 'o':
                return O;
            case 'p':
                return P;
            case 'q':
                return Q;
            case 'r':
                return R;
            case 's':
                return S;
            case 't':
                return T;
            case 'u':
                return U;
            case 'v':
                return V;
            case 'w':
                return W;
            case 'x':
                return X;
            case 'y':
                return Y;
            case 'z':
                return Z;
            default:
                return null;
        }
    }

    /**
     * 返回拼接好的查询首字母列表查询sql语句<br/>
     * 注意：查询对象应该使用distinct过滤掉重复值
     *
     * @param parName 查询字段名，如:c.COMPANY_NAME
     * @param parameterMap 参数map，为null则将参数值直接拼接在sql中返回
     * @param searchChars 查询首字母列表(大小写字母、汉字、各种字符均可)
     * @return
     */
    public static String getFirstCharSearchSql(String parName, Map<String, Object> parameterMap, String... searchChars) {
        StringBuilder sqlBuilder = new StringBuilder();
        boolean hasCode = false;
        if (searchChars != null && searchChars.length > 0) {
            int index = 0;
            if (searchChars.length == 1) {
                String searchChar = searchChars[0];
                if (searchChar != null && searchChar.length() > 0) {
                    if (!searchChar.trim().isEmpty()) {
                        int added = 0;
                        for (int i = 1; i <= searchChar.length(); i++) {
                            String s = searchChar.substring(i - 1, i);
                            if (!" ".equals(s)) {
                                if (!hasCode) {
                                    hasCode = true;
                                }

                                char c = searchChar.toUpperCase().charAt(i - 1);
                                int[] range = getCharRange(c);
                                if (added > 0) {
                                    sqlBuilder.append(" AND (");
                                } else {
                                    sqlBuilder.append("(");
                                }
                                if (range != null && range.length > 1) {
                                    String sql = "CONV(HEX(SUBSTR(CONVERT(" + parName + " USING gbk)," + i + ", 1)),16,10) BETWEEN ";
                                    sqlBuilder.append(sql);
                                    if (parameterMap != null) {
                                        sqlBuilder.append(":pinyin_search_char_index").append(index++).append(" AND :pinyin_search_char_index").append(index++).append(" OR ");
                                        parameterMap.put("pinyin_search_char_index" + (index - 2), range[0]);
                                        parameterMap.put("pinyin_search_char_index" + (index - 1), range[1]);
                                    } else {
                                        sqlBuilder.append(range[0]).append(" AND ").append(range[1]).append(" OR ");
                                    }
                                }
                                if (range != null) {
                                    if (parameterMap != null) {
                                        String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++) + " OR SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++);
                                        sqlBuilder.append(sql);
                                        parameterMap.put("pinyin_search_char_index" + (index - 2), s.toLowerCase());
                                        parameterMap.put("pinyin_search_char_index" + (index - 1), s.toUpperCase());
                                    } else {
                                        String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s.toLowerCase() + "' OR SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s.toUpperCase() + "'";
                                        sqlBuilder.append(sql);
                                    }
                                } else {
                                    if (parameterMap != null) {
                                        String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++);
                                        sqlBuilder.append(sql);
                                        parameterMap.put("pinyin_search_char_index" + (index - 1), s);
                                    } else {
                                        String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s + "'";
                                        sqlBuilder.append(sql);
                                    }
                                }
                                sqlBuilder.append(")");
                                added++;
                            }
                        }
                        /*
                         if (added > 0) {
                         sqlBuilder.append(" OR ");
                         }
                         String sql = parName + " LIKE '" + searchChar + "%'";
                         sqlBuilder.append(sql);
                         */
                    }
                }
            } else {
                int j = 0;
                for (String searchChar : searchChars) {
                    if (searchChar != null && searchChar.length() > 0) {
                        if (!searchChar.trim().isEmpty()) {
                            if (j > 0) {
                                sqlBuilder.append(" OR (");
                            } else {
                                sqlBuilder.append("(");
                            }
                            int added = 0;
                            for (int i = 1; i <= searchChar.length(); i++) {
                                String s = searchChar.substring(i - 1, i);
                                if (!" ".equals(s)) {
                                    if (!hasCode) {
                                        hasCode = true;
                                    }

                                    char c = searchChar.toUpperCase().charAt(i - 1);
                                    int[] range = getCharRange(c);
                                    if (added > 0) {
                                        sqlBuilder.append(" AND (");
                                    } else {
                                        sqlBuilder.append("(");
                                    }
                                    if (range != null && range.length > 1) {
                                        String sql = "CONV(HEX(SUBSTR(CONVERT(" + parName + " USING gbk)," + i + ", 1)),16,10) BETWEEN ";
                                        sqlBuilder.append(sql);
                                        if (parameterMap != null) {
                                            sqlBuilder.append(":pinyin_search_char_index").append(index++).append(" AND :pinyin_search_char_index").append(index++).append(" OR ");
                                            parameterMap.put("pinyin_search_char_index" + (index - 2), range[0]);
                                            parameterMap.put("pinyin_search_char_index" + (index - 1), range[1]);
                                        } else {
                                            sqlBuilder.append(range[0]).append(" AND ").append(range[1]).append(" OR ");
                                        }
                                    }
                                    if (range != null) {
                                        if (parameterMap != null) {
                                            String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++) + " OR SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++);
                                            sqlBuilder.append(sql);
                                            parameterMap.put("pinyin_search_char_index" + (index - 2), s.toLowerCase());
                                            parameterMap.put("pinyin_search_char_index" + (index - 1), s.toUpperCase());
                                        } else {
                                            String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s.toLowerCase() + "' OR SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s.toUpperCase() + "'";
                                            sqlBuilder.append(sql);
                                        }
                                    } else {
                                        if (parameterMap != null) {
                                            String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE :pinyin_search_char_index" + (index++);
                                            sqlBuilder.append(sql);
                                            parameterMap.put("pinyin_search_char_index" + (index - 1), s);
                                        } else {
                                            String sql = "SUBSTR(" + parName + ", " + i + ", 1) LIKE '" + s + "'";
                                            sqlBuilder.append(sql);
                                        }
                                    }
                                    sqlBuilder.append(")");
                                    added++;
                                }
                            }
                            /*
                             if (added > 0) {
                             sqlBuilder.append(" OR ");
                             }
                             String sql = parName + " LIKE '" + searchChar + "%'";
                             sqlBuilder.append(sql);
                             */
                            sqlBuilder.append(")");
                            j++;
                        }
                    }
                }
            }
        }
        if (hasCode) {
            sqlBuilder.insert(0, "(");
            sqlBuilder.append(")");
        }
        return sqlBuilder.toString();
    }

    /**
     * 将字符串中的中文转化为拼音,其他字符不变
     *
     * @param inputString
     * @return
     */
    public static String getPingYin(String inputString) {
        if(inputString!=null){
            StringBuilder output = new StringBuilder();
            char[] input = inputString.toCharArray();

            HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
            defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
            defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
            defaultFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
            for (int i = 0; i < input.length; i++) {
                try {
                    if (java.lang.Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) {
                        String[] temp = PinyinHelper.toHanyuPinyinStringArray(input[i], defaultFormat);
                        if (temp != null && temp[0] != null) {
                            output.append(temp[0]);
                        }
                    } else {
                        output.append(java.lang.Character.toString(input[i]));
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    log.log(Level.WARNING, null, e);
                }
            }
            return output.toString();
        }
        return null;
    }

    /**
     * 获取汉字串拼音首字母，英文字符不变
     *
     * @param inputString 汉字串
     * @return 汉语拼音首字母
     */
    public static String getFirstSpell(String inputString) {
        if(inputString!=null){
            StringBuilder output = new StringBuilder();
            char[] arr = inputString.toCharArray();
            HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
            defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
            defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
            defaultFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
            for (int i = 0; i < arr.length; i++) {
                try {
                    if (arr[i] > 128) {
                        String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat);
                        if (temp != null && temp[0] != null && temp[0].length()>0) {
                            output.append(temp[0].charAt(0));
                        }
                    } else {
                        output.append(arr[i]);
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    log.log(Level.WARNING, null, e);
                }
            }
            return output.toString();
        }
        return null;
    }
    

    public static String camelString(String value,String spliter){
    	if(StringUtils.isEmpty(spliter)) {
    		spliter = "_";
    	}
		String str = value;
		str = str.toLowerCase();
		Pattern p = Pattern.compile("("+spliter+"\\w)");
		Matcher m = p.matcher(str);
		while(m.find()){
			str = str.replaceAll(m.group(1), m.group(1).toUpperCase());
		}
		return str.replaceAll(spliter, "");
    }
}
